Django拓展auth 用户
完成注册登录登出注销操作
!!!拓展auth用户请务必在 python manage.py migrate
前进行!!!
新建一个project:
closetUsers
修改
settings.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#closetUsers/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users', # modify
'rest_framework', # modify
'django_filters', # modify
]
#update database config
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'closetUser',
'USER': 'may',
'PASSWORD': 'may233',
'HOST': '120.76.62.132',
'PORT': '3306',
}
}
#add auth_user_model !after! add the extended user
AUTH_USER_MODEL = 'users.User' #pattern: <appName>.<className>新建一个app:
users
修改
users/__init__.py
1
2
3
4#users/__init__.py
import pymysql
pymysql.install_as_MySQLdb()
#use for django2.x version to link mysql database在
users
底下添加文件urls.py
,修改closetUsers.urls.py
1
2
3
4
5
6
7
8
9
10#closetUsers/urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import include #add this
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('users.urls')),
#add this, pattern: <appName>.urls
]修改
users.models.py
, 添加拓展的用户类,继承自 AbstractUser, 注:如原来的auth.User 已有的属性不需要再添加1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#users/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
"""
save the user info
"""
style = models.CharField(max_length=30, default='casual', null=True, blank=True)
profile = models.URLField(default='http://120.76.62.132:8080/photos/40padded.jpg', blank=True)
phone = models.CharField(max_length=11, null=True, blank=True)
def __str__(self):
return self.username建表
1
2
3xxxdeMacBook-Pro:closetUsers xxx$ python3 manage.py migrate
xxxdeMacBook-Pro:closetUsers xxx$ python3 manage.py makemigrations users
xxxdeMacBook-Pro:closetUsers xxx$ python3 manage.py migrate users重写UserCreationForm, UserChangeForm, 在users 底下新建 form.py文件,其实我只是想要提供一个restful的API而不是建立一个网站,因而应该不需要使用到表单创建,但Django文档中说明拓展User需要重写这两个表单因此还是重写了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#users/forms.py
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django import forms
from .models import User
class RegisterForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = ('username', 'email', 'phone', 'style', 'profile')
# check if email is valid
def clean_email(self):
email = self.cleaned_data['email']
users = User.objects.filter(email=email)
if users:
raise forms.ValidationError("该邮箱已注册过,尝试登录?")
return email
class ChangeInfoForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = User
fields = ('username', 'email', 'phone', 'style', 'profile')
一、注册
法一:暴力解决
在 views.py中添加相关类或函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#users/views.py
from django.shortcuts import render
from django.http import JsonResponse, HttpResponse
from rest_framework import status
from .models import User
# Create your views here.
def sign_up(request):
username = request.data['username']
password = request.data['password']
users = User.objects.filter(username=username)
if users:
return HttpResponse('该用户已存在', status=status.HTTP_400_BAD_REQUEST)
user = User.objects.create_user(username=username, password=password)
return HttpResponse('创建成功,登录?', status=status.HTTP_200_OK)在 urls.py 中添加相关路径
1
2
3
4
5
6
7
8#users/urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from users import views
urlpatterns = format_suffix_patterns([
path('users/add1/', views.sign_up),
])使用 httpie 模拟post请求
1
2
3pattern: http post <urlAddress> @<jsonFileAddress>
xxxdeMacBook-Pro:closetUsers xxx$ http --json post http://127.0.0.1:8000/users/add1/ @/Users/xxx/Desktop/closet/jsonTest/login.json
HTTP/1.1 403 ForbiddenError: HTTP/1.1 403 Forbidden, CSRF verification failed. Request aborted.
Solve: 为了防止跨站伪造请求,django引入了csrf机制,引入csrf_exempt
1
2
3
4
5
6#users/views.py
from django.views.decorators.csrf import csrf_exempt
def sign_up(request):
passError: HTTP/1.1 500 Internal Server Error,继续看报错信息,发现进行sign_up函数解析后出现错误,发现是request以json格式发送请求时,无法以
request.data['username']
的方式获取数据Solve:
1
2
3
4
5
6
7#users/views.py inside sign_up function
import json
post_body = request.body
#django2.x use body, while django1.x use raw_post_data
data = json.loads(post_body)
username = data['username']
password = data['password']再次尝试使用httpie发送请求,成功!开心!
1
2
3
4
5
6
7
8
9
10
11xxxdeMacBook-Pro:closetUsers xxx$ http --json post http://127.0.0.1:8000/users/add1/ @/Users/xxx/Desktop/closet/jsonTest/login.json
HTTP/1.1 200 OK
Content-Length: 24
Content-Type: text/html; charset=utf-8
Date: Sat, 22 Dec 2018 05:17:42 GMT
Server: WSGIServer/0.2 CPython/3.7.0
X-Frame-Options: SAMEORIGIN
创建成功,登录?
xxxdeMacBook-Pro:closetUsers xxx$以上只是简单的注册,下面我们来拓展一下,加上对于信息的验证,加上了对于手机号码和邮箱的格式验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63#users/views.py
from django.http import JsonResponse, HttpResponse
from rest_framework import status
from .models import User
from django.views.decorators.csrf import csrf_exempt
import json
from django.contrib.auth import login, authenticate, logout
import re
# Create your views here.
def sign_up(request):
if request.method == 'POST':
post_body = request.body
data = json.loads(post_body)
if 'username' in data:
username = data['username']
else:
username = 'may'
password = data['password']
if 'email' in data:
email = data['email']
# check if email is valid
email_pat = re.compile(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$')
if not re.match(email_pat, email):
return JsonResponse(data={"msg": "请输入正确的邮箱名"}, status=status.HTTP_400_BAD_REQUEST)
else:
email = 'error'
if 'phone' in data:
phone = data['phone']
# check if phone is valid
phone_pat = re.compile(r'^(13\d|14[5|7]|15\d|166|17[3|6|7]|18\d)\d{8}$')
if not re.match(phone_pat, phone):
return JsonResponse(data={"msg": "请输入正确的手机号"}, status=status.HTTP_400_BAD_REQUEST)
else:
phone = 'error'
if 'profile' in data:
profile = data['profile']
else:
profile = 'http://120.76.62.132:8080/photos/default.jpg'
if 'style' in data:
style = data['style']
else:
style = 'casual'
# users = User.objects.filter(username=username)
email_users = User.objects.filter(email=email)
phone_users = User.objects.filter(phone=phone)
name_users = User.objects.filter(username=username)
if email_users:
return JsonResponse(data={"msg": "该邮箱已注册过"}, status=status.HTTP_400_BAD_REQUEST)
if phone_users:
return JsonResponse(data={"msg": "该手机号已注册过"}, status=status.HTTP_400_BAD_REQUEST)
if name_users:
return JsonResponse(data={"msg": "该用户已存在"}, status=status.HTTP_400_BAD_REQUEST)
if email == 'error':
email = ''
if phone == 'error':
phone = ''
user = User.objects.create_user(username=username, password=password, email=email,
phone=phone, style=style, profile=profile)
return JsonResponse(data={"msg": "创建成功,登录?"}, status=status.HTTP_200_OK)
法二:django-rest-framework
尝试用django-rest-framework提供的方法实现
二、登录
法一:沿袭我们的暴力方案
2.1 使用auth模块提供的login
使用username和password登录
1 | #users/views.py |
2.2 拓展,自定义后端,使用邮箱登录
添加 backends.py文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23from .models import User
class EmailBackend(object):
def authenticate(self, request, **credentials):
# 要注意登录表单中用户输入的用户名或者邮箱的 field 名均为 username
email = credentials.get('email', credentials.get('username'))
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
pass
else:
if user.check_password(credentials["password"]):
return user
def get_user(self, user_id):
"""
该方法是必须的
"""
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None在 setttings.py 中加入后端文件告诉Django 你使用了自定义后端
1
2
3
4
5AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'users.backends.EmailBackend',
'users.backends.PhoneBackend',
)
2.3 同理拓展,自定义后端,使用手机登录
代码大同小异,不赘述了
三、登出
法一:继续,暴力解决一切事物
1 | #users/views.py |
四、注销
法一:继续,暴力解决一切事物
1 | #users/views.py |